<template>
    <transition name="viewer-fade">
        <div tabindex="-1" ref="el-image-viewer__wrapper" class="el-image-viewer__wrapper" :style="{ 'z-index': viewerZIndex }">
            <div class="el-image-viewer_fileName" v-if="current">{{ current.fileName }}</div>
            <div class="el-image-viewer__mask"></div>
            <!-- CLOSE -->
            <span class="el-image-viewer__btn el-image-viewer__close" @click="hide">
                <i class="el-icon-close"></i>
            </span>
            <!-- ARROW -->
            <template v-if="!isSingle">
                <span class="el-image-viewer__btn el-image-viewer__prev" :class="{ 'is-disabled': !infinite && isFirst }" @click="prev">
                    <i class="el-icon-arrow-left" />
                </span>
                <span class="el-image-viewer__btn el-image-viewer__next" :class="{ 'is-disabled': !infinite && isLast }" @click="next">
                    <i class="el-icon-arrow-right" />
                </span>
            </template>
            <!-- ACTIONS -->
            <div class="el-image-viewer__btn el-image-viewer__actions">
                <div class="el-image-viewer__actions__inner">
                    <i class="el-icon-zoom-out" @click="handleActions('zoomOut')"></i>
                    <i class="el-icon-zoom-in" @click="handleActions('zoomIn')"></i>
                    <i :class="mode.icon" @click="toggleMode"></i>
                    <i class="el-image-viewer__actions__divider"></i>
                    <span> {{ index + 1 }} / {{ files.length }}</span>
                    <i class="el-image-viewer__actions__divider"></i>
                    <i class="el-icon-download" @click="download" v-if="showDownload"></i>
                    <i class="el-icon-refresh-left" @click="handleActions('anticlocelise')"></i>
                    <i class="el-icon-refresh-right" @click="handleActions('clocelise')"></i>
                </div>
            </div>
            <!-- CANVAS -->
            <div class="el-image-viewer__canvas" v-if="current">
                <div :style="imgStyle" class="content">
                    <img
                        ref="img"
                        class="el-image-viewer__img"
                        :src="current.resourceUrl"
                        @load="handleImgLoad"
                        @error="handleImgError"
                        @mousedown="handleMouseDown"
                        v-if="current.resourceType == 1"
                    />
                    <video-player class="video video-player vjs-custom-skin" :playsinline="true" :options="vedioOption" v-if="current.resourceType == 2" />
                    <DocumentPreview :resourceUrl="current.resourceUrl" :fileName="current.fileName" v-else-if="current.resourceType == 3" />
                </div>
            </div>
        </div>
    </transition>
</template>

<script>
import { on, off } from 'element-ui/src/utils/dom'
import { rafThrottle, isFirefox } from 'element-ui/src/utils/util'
import DocumentPreview from './DocumentPreview.vue'
import { downloadByUrl } from '@/utils/download'
import { nextPopupZindex } from '@/utils/ui/elementUiExtend'

const Mode = {
    CONTAIN: {
        name: 'contain',
        icon: 'el-icon-full-screen'
    },
    ORIGINAL: {
        name: 'original',
        icon: 'el-icon-c-scale-to-original'
    }
}

const mousewheelEventName = isFirefox() ? 'DOMMouseScroll' : 'mousewheel'

export default {
    name: 'EventFilePreview',
    components: { DocumentPreview },
    props: {
        /**
        * @param {Array} files 文件列表
        * [{
        *  "fileName"：""， //文件名
            "resourceId"：1704162068806，//资源ID
            "resourceType"：1，//资源类型：1:图片 2:视频 3:文件
            "resourceUrl"：""，  //资源url
          }]
        *
        */
        files: {
            type: Array,
            default: () => [],
            required: true
        },
        initialIndex: {
            type: Number,
            default: 0
        },
        zIndex: {
            type: Number
        },
        onSwitch: {
            type: Function,
            default: () => {}
        },
        onClose: {
            type: Function,
            default: () => {}
        },

        // 是否显示下载按钮
        showDownload: {
            type: Boolean,
            default: true
        }
    },

    data() {
        return {
            index: this.initialIndex,
            isShow: false,
            infinite: true,
            loading: false,
            transform: {
                scale: 1,
                deg: 0,
                offsetX: 0,
                offsetY: -30,
                enableTransition: false
            },
            mode: Mode.CONTAIN,
            playerOptions: {
                playbackRates: [0.5, 1.0, 1.5, 2.0], //播放速度
                autoplay: false, //如果true,浏览器准备好时开始回放。
                loop: false, // 导致视频一结束就重新开始。
                muted: true, // 默认情况下将会消除任何音频。
                preload: 'auto', // 建议浏览器在<video>加载元素后是否应该开始下载视频数据。auto浏览器选择最佳行为,立即开始加载视频（如果浏览器支持）
                language: 'zh-CN',
                fluid: true, // 当true时，Video.js player将拥有流体大小。换句话说，它将按比例缩放以适应其容器。
                hls: false,
                sources: [
                    {
                        // type: 'application/x-mpegURL',
                        type: 'video/mp4',
                        src: ''
                    }
                ],
                aspectRatio: '16:9',
                poster: '', // 封面地址
                choosed: false, //被选中的
                notSupportedMessage: '视频录像服务维护中', //允许覆盖Video.js无法播放媒体源时显示的默认信息。
                controlBar: {
                    timeDivider: false,
                    durationDisplay: false,
                    remainingTimeDisplay: false,
                    fullscreenToggle: false //全屏按钮
                }
            }
        }
    },
    computed: {
        isSingle() {
            return this.files.length <= 1
        },
        isFirst() {
            return this.index === 0
        },
        isLast() {
            return this.index === this.files.length - 1
        },
        current() {
            return this.files[this.index]
        },
        // 图片样式
        imgStyle() {
            const { scale, deg, offsetX, offsetY, enableTransition } = this.transform
            const style = {
                transform: `translateX(${offsetX}px) translateY(${offsetY}px) scale(${scale}) rotate(${deg}deg)`,
                transition: enableTransition ? 'transform .3s' : '',
                transformOrigin: 'center center'
            }
            if (this.mode === Mode.CONTAIN) {
                style.maxWidth = style.maxHeight = '100%'
            }
            return style
        },
        // 视频播放器配置
        vedioOption() {
            if (!this.current || this.current.resourceType != 2) {
              return
            }
            return {
                ...this.playerOptions,
                sources: [
                    {
                        type: 'video/mp4',
                        src: this.current.resourceUrl
                    }
                ]
            }
        },
        viewerZIndex() {
            return this.zIndex || nextPopupZindex()
        }
    },
    watch: {
        index: {
            handler: function(val) {
                this.reset()
                this.onSwitch(val)
            }
        },
        currentImg(val) {
            this.$nextTick((_) => {
                const $img = this.$refs.img[0]
                if (!$img.complete) {
                    this.loading = true
                }
            })
        }
    },
    methods: {
        hide() {
            this.deviceSupportUninstall()
            this.onClose()
        },
        deviceSupportInstall() {
            const _this = this
            this._keyDownHandler = rafThrottle((e) => {
                const keyCode = e.keyCode
                switch (keyCode) {
                    // ESC
                    case 27:
                        this.hide()
                        break
                    // SPACE
                    case 32:
                        this.toggleMode()
                        break
                    // LEFT_ARROW
                    case 37:
                        this.prev()
                        break
                    // UP_ARROW
                    case 38:
                        this.handleActions('zoomIn')
                        break
                    // RIGHT_ARROW
                    case 39:
                        this.next()
                        break
                    // DOWN_ARROW
                    case 40:
                        this.handleActions('zoomOut')
                        break
                }
            })
            this._mouseWheelHandler = rafThrottle((e) => {
                if (_this.current?.resourceType == '3') {
                  return
                }
                const delta = e.wheelDelta ? e.wheelDelta : -e.detail
                if (delta > 0) {
                    this.handleActions('zoomIn', {
                        zoomRate: 0.015,
                        enableTransition: false
                    })
                } else {
                    this.handleActions('zoomOut', {
                        zoomRate: 0.015,
                        enableTransition: false
                    })
                }
            })
            on(document, 'keydown', this._keyDownHandler)
            on(document, mousewheelEventName, this._mouseWheelHandler)
        },
        deviceSupportUninstall() {
            off(document, 'keydown', this._keyDownHandler)
            off(document, mousewheelEventName, this._mouseWheelHandler)
            this._keyDownHandler = null
            this._mouseWheelHandler = null
        },
        handleImgLoad(e) {
            this.loading = false
        },
        handleImgError(e) {
            this.loading = false
            e.target.alt = '加载失败'
        },

        // 处理滚动事件
        handleMouseDown(e) {
            if (this.loading || e.button !== 0) {
              return
            }

            const { offsetX, offsetY } = this.transform
            const startX = e.pageX
            const startY = e.pageY
            this._dragHandler = rafThrottle((ev) => {
                this.transform.offsetX = offsetX + ev.pageX - startX
                this.transform.offsetY = offsetY + ev.pageY - startY
            })
            on(document, 'mousemove', this._dragHandler)
            on(document, 'mouseup', (ev) => {
                off(document, 'mousemove', this._dragHandler)
            })

            e.preventDefault()
        },
        reset() {
            this.transform = {
                scale: 1,
                deg: 0,
                offsetX: 0,
                offsetY: 0,
                enableTransition: false
            }
        },
        toggleMode() {
            if (this.loading) {
              return
            }
            const modeNames = Object.keys(Mode)
            const modeValues = Object.values(Mode)
            const index = modeValues.indexOf(this.mode)
            const nextIndex = (index + 1) % modeNames.length
            this.mode = Mode[modeNames[nextIndex]]
            this.reset()
        },
        prev() {
            if (this.isFirst && !this.infinite) {
              return
            }
            const len = this.files.length
            this.index = (this.index - 1 + len) % len
        },
        next() {
            if (this.isLast && !this.infinite) {
              return
            }
            const len = this.files.length
            this.index = (this.index + 1) % len
        },

        // 按钮整合处理
        handleActions(action, options = {}) {
            if (this.loading) {
              return
            }
            const { zoomRate, rotateDeg, enableTransition } = {
                zoomRate: 0.2,
                rotateDeg: 90,
                enableTransition: true,
                ...options
            }
            const { transform } = this
            switch (action) {
                case 'zoomOut':
                    if (transform.scale > 0.2) {
                        transform.scale = parseFloat((transform.scale - zoomRate).toFixed(3))
                    }
                    break
                case 'zoomIn':
                    transform.scale = parseFloat((transform.scale + zoomRate).toFixed(3))
                    break
                case 'clocelise':
                    transform.deg += rotateDeg
                    break
                case 'anticlocelise':
                    transform.deg -= rotateDeg
                    break
            }
            transform.enableTransition = enableTransition
        },
        download() {
            if (!this.current) {
              return
            }
            const { fileName, resourceUrl } = this.current
            downloadByUrl(resourceUrl, fileName)
        }
    },
    mounted() {
        this.deviceSupportInstall()
    }
}
</script>
<style lang="scss" scoped>
.el-image-viewer__close {
    top: 20px;
    right: 40px;
    width: 40px;
    height: 40px;
    font-size: 25px;
    color: #fff;
}
.el-image-viewer__prev,
.el-image-viewer__next {
    width: 45px;
    height: 60px;
    font-size: 30px;
    background-color: transparent;
}
.el-image-viewer__close:hover,
.el-image-viewer__prev:hover,
.el-image-viewer__next:hover {
    background-color: #606266;
}
.el-image-viewer__btn {
    border-radius: 4px;
}
.el-image-viewer__actions {
    width: 350px;
    cursor: auto;
    .el-image-viewer__actions__inner > i {
        cursor: pointer;
    }
    .el-image-viewer__actions__inner > i:hover {
        color: #dfdfdf;
    }
    .el-image-viewer__actions__inner > span {
        font-size: 16px;
    }
}
.el-image-viewer__canvas {
    color: #ffffff;
    font-size: 14px;
    display: flex;
    justify-content: center;
    align-items: center;
    .content {
        width: 80%;
        height: 80%;
        display: flex;
        align-items: center;
        justify-content: center;
        .video-player {
            height: 100%;
            width: 90%;
        }
    }
    .el-image-viewer__img {
        max-width: 100%;
        max-height: 100%;
    }
}
.el-image-viewer_fileName {
    position: absolute;
    left: 50%;
    top: 30px;
    color: #fff;
    font-size: 22px;
    transform: translateX(-50%);
    z-index: 1;
    text-shadow: 0 0 #333;
    width: 60%;
    text-align: center;
    text-overflow: ellipsis;
    overflow: hidden;
    white-space: nowrap;
}
</style>
